#include "internal.h"

static void switched_from_dl(struct rq *rq, struct task_struct *p)
{
    /*
     * task_non_contending() can start the "inactive timer" (if the 0-lag
     * time is in the future). If the task switches back to dl before
     * the "inactive timer" fires, it can continue to consume its current
     * runtime using its current deadline. If it stays outside of
     * SCHED_DEADLINE until the 0-lag time passes, inactive_task_timer()
     * will reset the task parameters.
     */
    if (task_on_rq_queued(p) && p->dl.dl_runtime)
        task_non_contending(&p->dl);

    /*
     * In case a task is setscheduled out from SCHED_DEADLINE we need to
     * keep track of that on its cpuset (for correct bandwidth tracking).
     */
    dec_dl_tasks_cs(p);

    if (!task_on_rq_queued(p))
    {
        /*
         * Inactive timer is armed. However, p is leaving DEADLINE and
         * might migrate away from this rq while continuing to run on
         * some other class. We need to remove its contribution from
         * this rq running_bw now, or sub_rq_bw (below) will complain.
         */
        if (p->dl.dl_non_contending)
            sub_running_bw(&p->dl, &rq->dl);
        sub_rq_bw(&p->dl, &rq->dl);
    }

    /*
     * We cannot use inactive_task_timer() to invoke sub_running_bw()
     * at the 0-lag time, because the task could have been migrated
     * while SCHED_OTHER in the meanwhile.
     */
    if (p->dl.dl_non_contending)
        p->dl.dl_non_contending = 0;

    /*
     * Since this might be the only -deadline task on the rq,
     * this is the right place to try to pull some other one
     * from an overloaded CPU, if any.
     */
    if (!task_on_rq_queued(p) || rq->dl.dl_nr_running)
        return;

    deadline_queue_pull_task(rq);
}
